package svm_ddag;

import param.Kernel;
import libsvm.svm_model;
import libsvm.svm_node;
import libsvm.svm_parameter;

public class DDAG {

	public static double ddag_predict_values(svm_model model, svm_node[] x, double[] dec_values) {
		int i;
		if (model.param.svm_type == svm_parameter.ONE_CLASS || model.param.svm_type == svm_parameter.EPSILON_SVR
				|| model.param.svm_type == svm_parameter.NU_SVR) {
			double[] sv_coef = model.sv_coef[0];
			double sum = 0;
			for (i = 0; i < model.l; i++)
				sum += sv_coef[i] * Kernel.k_function(x, model.SV[i], model.param);
			sum -= model.rho[0];
			dec_values[0] = sum;

			if (model.param.svm_type == svm_parameter.ONE_CLASS)
				return (sum > 0) ? 1 : -1;
			else
				return sum;
		} else {
			int nr_class = model.nr_class;
			int l = model.l;

			double[] kvalue = new double[l];
			for (i = 0; i < l; i++)
				kvalue[i] = Kernel.k_function(x, model.SV[i], model.param);

			int[] start = new int[nr_class];
			start[0] = 0;
			for (i = 1; i < nr_class; i++)
				start[i] = start[i - 1] + model.nSV[i - 1];

			int[] vote = new int[nr_class];
			for (i = 0; i < nr_class; i++)
				vote[i] = 0;

			ddag_recursive(start, 0, 1, model, kvalue, dec_values, 0, vote);
			int vote_max_idx = 0;
			for (i = 1; i < nr_class; i++)
				if (vote[i] > vote[vote_max_idx])
					vote_max_idx = i;

			return model.label[vote_max_idx];
		}
	}

	public static double ddag_predict(svm_model model, svm_node[] x) {
		int nr_class = model.nr_class;
		double[] dec_values;
		if (model.param.svm_type == svm_parameter.ONE_CLASS || model.param.svm_type == svm_parameter.EPSILON_SVR
				|| model.param.svm_type == svm_parameter.NU_SVR)
			dec_values = new double[1];
		else
			dec_values = new double[nr_class - 1];
		double pred_result = ddag_predict_values(model, x, dec_values);
		return pred_result;
	}

	private static void ddag_recursive(int[] start, int i, int j, svm_model model, double[] kvalue,
			double[] dec_values, int temp, int[] vote) {
		int p = (j - i - 1) + model.nr_class * i - i * (i + 1) / 2;
		// temp=0, i=0, j=1, p=0
		temp++;
		double sum = 0;
		int si = start[i];
		int sj = start[j];
		int ci = model.nSV[i];
		int cj = model.nSV[j];

		int k;
		double[] coef1 = model.sv_coef[j - 1];
		double[] coef2 = model.sv_coef[i];
		for (k = 0; k < ci; k++)
			sum += coef1[si + k] * kvalue[si + k];
		for (k = 0; k < cj; k++)
			sum += coef2[sj + k] * kvalue[sj + k];
		sum -= model.rho[p];
		dec_values[temp - 1] = sum;

		if (dec_values[temp - 1] > 0) {
			if (j + 1 < model.nr_class) {
				ddag_recursive(start, i, j + 1, model, kvalue, dec_values, temp, vote);
			} else {
				++vote[i];
			}
		} else {
			if (j + 1 < model.nr_class) {
				ddag_recursive(start, j, j + 1, model, kvalue, dec_values, temp, vote);
			} else {
				++vote[j];
			}
		}

	}
}
